package cn.com.hatech.blog.module.blog.controller;

import cn.com.hatech.blog.common.constant.ErrorCode;
import cn.com.hatech.blog.common.constant.Types;
import cn.com.hatech.blog.common.constant.WebConst;
import cn.com.hatech.blog.common.controller.BaseController;
import cn.com.hatech.blog.common.exception.TipException;
import cn.com.hatech.blog.common.result.RestResponse;
import cn.com.hatech.blog.common.utils.IpUtils;
import cn.com.hatech.blog.common.utils.TaleUtils;
import cn.com.hatech.blog.module.admin.article.entity.Article;
import cn.com.hatech.blog.module.admin.article.service.IArticleService;
import cn.com.hatech.blog.module.admin.article.vo.ArchiveVO;
import cn.com.hatech.blog.module.admin.category.entity.Meta;
import cn.com.hatech.blog.module.admin.category.service.IMetaService;
import cn.com.hatech.blog.module.admin.comment.entity.Comment;
import cn.com.hatech.blog.module.admin.comment.service.ICommentService;
import cn.com.hatech.blog.module.admin.comment.vo.CommentVO;
import cn.com.hatech.blog.module.admin.dashboard.service.ISiteService;
import cn.hutool.core.lang.Validator;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vdurmont.emoji.EmojiParser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.net.URLEncoder;
import java.util.List;

/**
 * @projectName: hatech-blog
 * @package: cn.com.hatech.blog.module.blog.controller
 * @className: IndexController
 * @author: xuruikai
 * @description: 首页控制器
 * @date: 2020/1/11 14:27
 * @version: 1.0
 */
@Controller
@Slf4j
public class IndexController extends BaseController {

    @Autowired
    private IArticleService contentService;

    @Autowired
    private ICommentService commentService;

    @Autowired
    private IMetaService metaService;

    @Autowired
    private ISiteService siteService;

    /**
     * 首页路由跳转
     *
     * @return
     */
    @GetMapping(value = {"/", "index"})
    public String index(HttpServletRequest request, @RequestParam(value = "limit", defaultValue = "9") int limit) {
        return this.index(request, 1, limit);
    }

    /**
     * 首页分页
     *
     * @param request request
     * @param p       第几页
     * @param limit   每页大小
     * @return 主页
     */
    @GetMapping(value = "page/{p}")
    public String index(HttpServletRequest request, @PathVariable int p, @RequestParam(value = "limit", defaultValue = "9") int limit) {
        p = p < 0 || p > WebConst.MAX_PAGE ? 1 : p;
        IPage<Article> articles = contentService.selectPublishContentPage(p, limit);
        request.setAttribute("articles", articles);
        if (p > 1) {
            this.title(request, "第" + p + "页");
        }
        return this.render("index");
    }

    /**
     * 文章页(预览)
     *
     * @param request 请求
     * @param cid     文章主键
     * @return
     */
    @GetMapping(value = {"article/{cid}", "article/{cid}/preview"})
    public String articlePreview(HttpServletRequest request, @PathVariable String cid) {
        Article contents = contentService.selectById(cid);
        if (null == contents) {
            return this.render404();
        }
        request.setAttribute("article", contents);
        request.setAttribute("is_post", true);
        completeArticle(request, contents);
        return this.render("post");
    }

    /**
     * 抽取公共方法
     *
     * @param request
     * @param contents
     */
    private void completeArticle(HttpServletRequest request, Article contents) {
        if (contents.getAllowComment()) {
            String cp = request.getParameter("cp");
            if (StringUtils.isEmpty(cp)) {
                cp = "1";
            }
            request.setAttribute("cp", cp);
            Page<CommentVO> commentsPaginator = commentService.getComments(contents.getId(), Integer.parseInt(cp), 6);
            request.setAttribute("comments", commentsPaginator);
        }
    }

    /**
     * 注销
     *
     * @param session
     * @param response
     */
    @RequestMapping("logout")
    public void logout(HttpSession session, HttpServletResponse response) {
        TaleUtils.logout(session, response);
    }


    /**
     * 归档页
     *
     * @return
     */
    @GetMapping(value = "archives")
    public String archives(HttpServletRequest request) {
        List<ArchiveVO> archives = siteService.getArchives();
        request.setAttribute("archives", archives);
        return this.render("archives");
    }


    /**
     * 根据分类名称查询
     *
     * @return
     */
    @GetMapping(value = "category/{keyword}")
    public String categories(HttpServletRequest request, @PathVariable String keyword, @RequestParam(value = "limit", defaultValue = "12") int limit) {
        return this.categories(request, keyword, 1, limit);
    }

    @GetMapping(value = "category/{keyword}/{page}")
    public String categories(HttpServletRequest request, @PathVariable String keyword, @PathVariable int page, @RequestParam(value = "limit", defaultValue = "12") int limit) {
        // TODO 和标签查询可以融合
        page = page < 0 || page > WebConst.MAX_PAGE ? 1 : page;
        Meta meta = metaService.getMeta(Types.CATEGORY.getType(), keyword);
        if (null == meta) {
            return this.render404();
        }
        IPage<Article> contentsPaginator = contentService.getArticles(meta.getId(), page, limit);
        request.setAttribute("articles", contentsPaginator);
        request.setAttribute("meta", meta);
        request.setAttribute("type", "分类");
        request.setAttribute("keyword", keyword);
        return this.render("page-category");
    }


    /**
     * 标签页
     *
     * @param name
     * @return
     */
    @GetMapping(value = "tag/{name}")
    public String tags(HttpServletRequest request, @PathVariable String name, @RequestParam(value = "limit", defaultValue = "12") int limit) {
        return this.tags(request, name, 1, limit);
    }

    /**
     * 标签分页
     *
     * @param request
     * @param name
     * @param page
     * @param limit
     * @return
     */
    @GetMapping(value = "tag/{name}/{page}")
    public String tags(HttpServletRequest request, @PathVariable String name, @PathVariable int page, @RequestParam(value = "limit", defaultValue = "12") int limit) {
        page = page < 0 || page > WebConst.MAX_PAGE ? 1 : page;
        // 对于空格的特殊处理
        name = name.replaceAll("\\+", " ");
        Meta meta = metaService.getMeta(Types.TAG.getType(), name);
        if (null == meta) {
            return this.render404();
        }
        IPage<Article> contentsPaginator = contentService.getArticles(meta.getId(), page, limit);
        request.setAttribute("articles", contentsPaginator);
        request.setAttribute("meta", meta);
        request.setAttribute("type", "标签");
        request.setAttribute("keyword", name);
        return this.render("page-category");
    }

    /**
     * 搜索页
     *
     * @param keyword
     * @return
     */
    @GetMapping(value = "search/{keyword}")
    public String search(HttpServletRequest request, @PathVariable String keyword, @RequestParam(value = "limit", defaultValue = "12") int limit) {
        return this.search(request, keyword, 1, limit);
    }

    @GetMapping(value = "search/{keyword}/{page}")
    public String search(HttpServletRequest request, @PathVariable String keyword, @PathVariable int page, @RequestParam(value = "limit", defaultValue = "12") int limit) {
        page = page < 0 || page > WebConst.MAX_PAGE ? 1 : page;
        IPage<Article> articles = contentService.getArticlesByKeyword(keyword, page, limit);
        request.setAttribute("articles", articles);
        request.setAttribute("type", "搜索");
        request.setAttribute("keyword", keyword);
        return this.render("page-category");
    }

    /**
     * 设置cookie
     *
     * @param name
     * @param value
     * @param maxAge
     * @param response
     */
    private void cookie(String name, String value, int maxAge, HttpServletResponse response) {
        Cookie cookie = new Cookie(name, value);
        cookie.setMaxAge(maxAge);
        cookie.setSecure(false);
        response.addCookie(cookie);
    }

    /**
     * 评论操作
     */
    @PostMapping(value = "comment")
    @ResponseBody
    @Transactional(rollbackFor = TipException.class)
    public RestResponse comment(HttpServletRequest request, HttpServletResponse response,
                                @RequestParam String articleId, @RequestParam String id,
                                @RequestParam String author, @RequestParam String mail,
                                @RequestParam String url, @RequestParam String text, @RequestParam String csrfToken) {

        String ref = request.getHeader("Referer");
        if (StringUtils.isEmpty(ref) || StringUtils.isEmpty(csrfToken)) {
            return RestResponse.fail(ErrorCode.BAD_REQUEST);
        }
        String token = cache.hget(Types.CSRF_TOKEN.getType(), csrfToken);
        if (StringUtils.isEmpty(token)) {
            return RestResponse.fail(ErrorCode.BAD_REQUEST);
        }

        if (null == articleId || StringUtils.isEmpty(text)) {
            return RestResponse.fail("请输入完整后评论");
        }

        if (StringUtils.isNotEmpty(author) && author.length() > 50) {
            return RestResponse.fail("姓名过长");
        }

        if (StringUtils.isNotEmpty(mail) && !Validator.isEmail(mail)) {
            return RestResponse.fail("请输入正确的邮箱格式");
        }
        if (StringUtils.isNotEmpty(url) && !Validator.isUrl(url)) {
            return RestResponse.fail("请输入正确的URL格式");
        }
        if (text.length() > 200) {
            return RestResponse.fail("请输入200个字符以内的评论");
        }

        String val = IpUtils.getIpAddrByRequest(request) + ":" + articleId;
        Integer count = cache.hget(Types.COMMENTS_FREQUENCY.getType(), val);
        if (null != count && count > 0) {
            return RestResponse.fail("您发表评论太快了，请过会再试");
        }

        author = TaleUtils.cleanXss(author);
        text = TaleUtils.cleanXss(text);

        author = EmojiParser.parseToAliases(author);
        text = EmojiParser.parseToAliases(text);

        Comment comments = new Comment();
        comments.setAuthor(author);
        comments.setArticleId(articleId);
        comments.setIp(request.getRemoteAddr());
        comments.setUrl(url);
        comments.setContent(text);
        comments.setMail(mail);
        comments.setParent(id);
        try {
            commentService.insertComment(comments);
            cookie("tale_remember_author", URLEncoder.encode(author, "UTF-8"), 7 * 24 * 60 * 60, response);
            cookie("tale_remember_mail", URLEncoder.encode(mail, "UTF-8"), 7 * 24 * 60 * 60, response);
            if (StringUtils.isNotEmpty(url)) {
                cookie("tale_remember_url", URLEncoder.encode(url, "UTF-8"), 7 * 24 * 60 * 60, response);
            }
            // 设置对每个文章1分钟可以评论一次
            cache.hset(Types.COMMENTS_FREQUENCY.getType(), val, 1, 60);
            return RestResponse.ok();
        } catch (Exception e) {
            String msg = "评论发布失败";
            if (e instanceof TipException) {
                msg = e.getMessage();
            } else {
                log.error(msg, e);
            }
            return RestResponse.fail(msg);
        }
    }

}
